package com.cbj.exp3;

import com.sun.org.apache.xpath.internal.operations.Bool;
import jdk.management.resource.internal.inst.SocketOutputStreamRMHooks;
import sun.security.action.PutAllAction;
import sun.text.resources.cldr.ii.FormatData_ii;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.time.format.SignStyle;
import java.util.*;

/**
 * @author Godc
 * @description
 */
public class OperatorAnalysis {
    static Set<Pair> firstVT = new HashSet<>();
    static Set<Pair> lastVT = new HashSet<>();
    static Map<Character,List<Character>> firstList = new HashMap<>();
    static Map<Character,List<Character>> lastList = new HashMap<>();
    static LinkedList<Pair> stack = new LinkedList<>();
    static List<String> production = new ArrayList<>();
    static List<Character> terminal = new ArrayList<>();
    static List<Character> unTerminal = new ArrayList<>();
    static Map<Pair,Character> table = new HashMap<>();
    static String handle = "";
    // 初始化终结符和非终结符
    static {
        terminal.add('+');
        terminal.add('-');
        terminal.add('*');
        terminal.add('/');
        terminal.add('(');
        terminal.add(')');
        terminal.add('i');
        terminal.add('#');
        unTerminal.add('E');
        unTerminal.add('T');
        unTerminal.add('F');
    }
    public static void main(String[] args) {
        ReadFromTxt();
        GetFirstVT();
        GetLastVT();
        buildTable();
        print();
        boolean analyze = analyze();
        System.out.println(handle.substring(0,handle.length()-1)+"的检测结果:"+analyze);
    }
    private static void print(){
        System.out.println("FirstVT集合:");
        System.out.println(firstList.toString());
        System.out.println("----------------------");
        System.out.println("LastVT集合:");
        System.out.println(lastList.toString());
        System.out.println("----------------------");
        System.out.println("优先关系表:");
        printTable();
        System.out.println("----------------------");
    }
    private static void buildTable(){
        for (String s : production) {
            List<String> strings = parseProduction(s);
            for (String string : strings) {
                char[] chars = string.toCharArray();
                for(int i = 0;i<chars.length-1;i++){
                    if(terminal.contains(chars[i])&&terminal.contains(chars[i+1])){
                        Pair pair = new Pair(chars[i],chars[i+1]);
                        table.put(pair,'=');
                    }
                    if(i+2<chars.length&&terminal.contains(chars[i])&&terminal.contains(chars[i+2])){
                        Pair pair = new Pair(chars[i],chars[i+2]);
                        table.put(pair,'=');
                    }
                    if(terminal.contains(chars[i])&&unTerminal.contains(chars[i+1])){
                        List<Character> list = firstList.get(chars[i + 1]);
                        for (Character ch : list) {
                            Pair pair = new Pair(chars[i], ch);
                            table.put(pair,'<');
                        }
                    }
                    if(unTerminal.contains(chars[i])&&terminal.contains(chars[i+1])){
                        List<Character> list = lastList.get(chars[i]);
                        for (Character ch : list) {
                            Pair pair = new Pair(ch, chars[i + 1]);
                            table.put(pair,'>');
                        }
                    }
                }
            }
        }
    }
    private static List<String> parseProduction(String str){
        str = str.substring(3, str.length());
        List<String> candidate = new ArrayList<>();
        if(str.indexOf("|")!=-1){
            String[] split = str.split("\\|");//注意需要转义
            for (String s : split) {
                candidate.add(s);
            }
        }else{
            candidate.add(str);
        }
        return candidate;
    }
    private static void GetFirstVT(){
        // 第一次添加
        for(int i = 0;i<production.size();i++){
            String str = production.get(i);
            char ch = str.charAt(0);// 产生式箭头左侧的推导字符
            List<String> candidate = parseProduction(str);
            for (String s : candidate) {
                for(int j = 0;j<s.length();j++){
                    if(terminal.contains(s.charAt(j))){
                        Pair pair = new Pair(ch,s.charAt(j));
                        insertFirstPair(pair);
                        break;
                    }
                }
            }
        }
        while(!stack.isEmpty()){
            Pair pair = stack.pop();
            char p = pair.p;
            for (String s : production) {
                char ch = s.charAt(0);
                List<String> strings = parseProduction(s);
                for (String string : strings) {
                    if(string.charAt(0)==p){
                        Pair insert = new Pair(ch,pair.a);
                        insertFirstPair(insert);
                    }
                }
            }
        }
        setToMap(firstVT,firstList);
    }
    private static void GetLastVT(){
        for(int i = 0;i<production.size();i++){
            String str = production.get(i);
            char ch = str.charAt(0);// 产生式箭头左侧的推导字符
            List<String> candidate = parseProduction(str);
            for (String s : candidate) {
                for(int j = s.length()-1;j>=0;j--){
                    if(terminal.contains(s.charAt(j))){
                        Pair pair = new Pair(ch,s.charAt(j));
                        insertLastPair(pair);
                        break;
                    }
                }
            }
        }
        while(!stack.isEmpty()){
            Pair pair = stack.pop();
            char p = pair.p;
            for (String s : production) {
                char ch = s.charAt(0);
                List<String> strings = parseProduction(s);
                for (String string : strings) {
                    if(string.charAt(string.length()-1)==p){
                        Pair insert = new Pair(ch,pair.a);
                        insertLastPair(insert);
                    }
                }
            }
        }
        setToMap(lastVT,lastList);
    }
    private static void ReadFromTxt() {
        File file = new File("D:\\idea_workspace\\operator-precedence-parsing\\src\\main\\java\\com\\cbj\\exp3\\content.txt");
        String str = null;
        try{
            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));//构造一个BufferedReader类来读取文件
            String s = null;
            while((s = br.readLine())!=null){//使用readLine方法，一次读一行
                production.add(s);
            }
            br.close();
        }catch(Exception e){
            e.printStackTrace();
        }
        handle = production.remove(production.size()-1);
        StringBuffer buffer = new StringBuffer(handle);
        for (int i = 0; i < buffer.length(); i++) {
            if(Character.isDigit(buffer.charAt(i)))
            buffer.setCharAt(i,'i');
        }
        handle = buffer.toString();
    }
    private static void insertFirstPair(Pair pair){
        if(!firstVT.contains(pair)){
            firstVT.add(pair);
            stack.push(pair);
        }
    }
    private static void insertLastPair(Pair pair){
        if(!lastVT.contains(pair)){
            lastVT.add(pair);
            stack.push(pair);
        }
    }
    private static void setToMap(Set<Pair> set,Map<Character,List<Character>> map){
        Iterator<Pair> iterator = set.iterator();
        while(iterator.hasNext()){
            Pair pair = iterator.next();
            if(map.containsKey(pair.p)){
                map.get(pair.p).add(pair.a);
            }else{
                ArrayList<Character> list = new ArrayList<>();
                list.add(pair.a);
                map.put(pair.p,list);
            }
        }
    }
    private static void printTable(){
        char[][] chars = new char[terminal.size() + 1][terminal.size() + 1];
        Set<Map.Entry<Pair, Character>> entries = table.entrySet();
        Iterator<Map.Entry<Pair, Character>> iterator = entries.iterator();
        while(iterator.hasNext()){
            Map.Entry<Pair, Character> next = iterator.next();
            int i = terminal.indexOf(next.getKey().p);
            int j = terminal.indexOf(next.getKey().a);
            chars[i][j] = next.getValue();
        }
        for (int i = 0; i < terminal.size(); i++) {
            System.out.print("\t");
            System.out.print(terminal.get(i));
        }
        System.out.println();
        for(int i = 0;i<terminal.size();i++){
            System.out.print(terminal.get(i)+"\t");
            for(int j = 0;j<terminal.size();j++){
                System.out.print(chars[i][j]+"\t");
            }
            System.out.println();
        }
    }
    private static char getRel(char ch1,char ch2){
        return table.get(new Pair(ch1,ch2));
    }
    /**
     * 规约
     * @param str 规约目的串
     * @param start 开始下标
     * @param end 结束下标
     * @return
     */
    private static char parse(String str,int start,int end){
        for (String s : production) {
            char N = s.charAt(0);
            List<String> strings = parseProduction(s);
            for (String string : strings) {
                int m = start,n = 0;
                while(m<=end&&n<string.length()){
                    char ch1 = str.charAt(m);
                    char ch2 = string.charAt(n);
                    if(string.length()!=end-start+1) break;
                    if(terminal.contains(ch1)&&terminal.contains(ch2)&&ch1==ch2){
                            m++;
                            n++;
                    }else if(unTerminal.contains(ch1)&&unTerminal.contains(ch2)){
                        m++;
                        n++;
                    }else{
                        break;
                    }
                }
                if(m==end+1){
                    return N;
                }
            }
        }
        return '#';
    }
    private static boolean analyze(){
        StringBuffer stack = new StringBuffer();
        try{
            stack.append('#');
            for(int i = 0;i<handle.length();i++){
                char a = handle.charAt(i);
                int j = stack.length()-1;
                if(!terminal.contains(stack.charAt(j))) j--;
                while(getRel(stack.charAt(j),a)=='>'){
                    char Q;
                    do{
                        Q = stack.charAt(j);
                        if(terminal.contains(stack.charAt(j-1))) j--;
                        else j = j-2;
                    }while(getRel(stack.charAt(j),Q)!='<');
                    // 执行规约
                    char parse = parse(stack.toString(), j + 1, stack.length() - 1);
                    stack.delete(j+1,stack.length());
                    stack.append(parse);
                }
                if(getRel(stack.charAt(j),a)=='<'||getRel(stack.charAt(j),a)=='='){
                    stack.append(a);
                }else{
                    throw new RuntimeException("输入串有误，调用出错侦查程序");
                }
            }
        }catch (Exception e){
            System.out.println("输入字符串有误或者不是满足的表达式");
        }
        return stack.charAt(0)=='#'&&unTerminal.contains(stack.charAt(1))&&stack.charAt(2)=='#';
    }

}
class Pair{
    // p为非终结符，a为终结符
    char p;
    char a;
    // 重写equals方法用于比较Pair对
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Pair)) return false;
        Pair pair = (Pair) o;
        return p == pair.p &&
                a == pair.a;
    }
    @Override
    public int hashCode() {
        return Objects.hash(p, a);
    }

    public Pair() {
    }

    public Pair(char p, char a) {
        this.p = p;
        this.a = a;
    }

    @Override
    public String toString() {
        return "Pair{" +
                "p=" + p +
                ", a=" + a +
                '}';
    }
}